package br.com.infoserver.volatilidade;

import java.util.ArrayList;
import java.util.List;

import br.com.infoserver.volatilidade.to.CalculoPrecoOpcaoTO;

/**
 * @since 13/05/2011
 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
 * 
 * descricao: Projeto Fase 2 - Interpolacao da curva de Vol (Volatilidade),
 * calculo de precos de opcoes utilizando as metodologias: Black&Scholes,
 * Binomial, Garman Kolhagen e Black. Mais o calculo das Gregas 
 * 
 */
public class Volatilidade {

	public static void main(String[] args) {
		System.out.println(">>>> Início - Volatilidade");

		Volatilidade vol = new Volatilidade();
		
		System.out.println("\tVolatilidade Apurada             : "
				+ vol.calculoVol(71, 31));
		
		System.out.println("\tMetodologia Black & Scholes(CALL): "
				+ vol.calculoPrecoBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL));
		System.out.println("\tMetodologia Black & Scholes(PUT) : "
				+ vol.calculoPrecoBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT));

		ArrayList<CalculoPrecoOpcaoTO> listCalculoPrecoOpcaoTO = new ArrayList<CalculoPrecoOpcaoTO>();
		CalculoPrecoOpcaoTO calPreOpcTO = new CalculoPrecoOpcaoTO();
			calPreOpcTO.setdS(120d);
			calPreOpcTO.setdX(100d);
			calPreOpcTO.setdVol(0.4d);
			calPreOpcTO.setDrF(0.1d);
			calPreOpcTO.setdT(1d);
			calPreOpcTO.setdQ(0d);
			calPreOpcTO.setdTipoOpcao(CalculoPrecoOpcaoValues.CALL);
		listCalculoPrecoOpcaoTO.add(calPreOpcTO);
		
//		ArrayList<Double> listResultadoCalculoPrecoOpcaoTO = new ArrayList<Double>();
//		listResultadoCalculoPrecoOpcaoTO = (ArrayList<Double>) vol.calculoPrecoBlackScholes(listCalculoPrecoOpcaoTO);

		
		
		
		System.out.println("\tMetodologia Binomial (CALL/AMERICANA): "
				+ vol.calculoPrecoBinomial(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL, 5d, EstiloValues.AMERICANA));
		System.out.println("\tMetodologia Binomial (CALL/EUROP�IA) : "
				+ vol.calculoPrecoBinomial(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL, 5d, EstiloValues.EUROPEIA));
		System.out.println("\tMetodologia Binomial (PUT/AMERICANA) : "
				+ vol.calculoPrecoBinomial(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT, 5d, EstiloValues.AMERICANA));
		System.out.println("\tMetodologia Binomial (PUT/EUROP�IA)  : "
				+ vol.calculoPrecoBinomial(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT, 5d, EstiloValues.EUROPEIA));
		
		System.out.println("\tMetodologia Garman-Kolhagen(CALL): "
				+ vol.calculoPrecoGarmanKolhagen(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL, 5d));
		System.out.println("\tMetodologia Garman-Kolhagen(PUT) : "
				+ vol.calculoPrecoGarmanKolhagen(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT, 5d));
		
		System.out.println("\tMetodologia Black(CALL): "
				+ vol.calculoPrecoBlack(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL, 5d));
		System.out.println("\tMetodologia Black(PUT) : "
				+ vol.calculoPrecoBlack(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT, 5d));

		System.out.println("\n");
		
		System.out.println("\tCálculo das Gregas - DELTA (CALL) : "
				+ vol.deltaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL));
		System.out.println("\tCálculo das Gregas - DELTA (PUT)  : "
				+ vol.deltaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT));

		System.out.println("\tCálculo das Gregas - GAMA         : "
				+ vol.gamaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d));
		
		System.out.println("\tCálculo das Gregas - THETA (CALL) : "
				+ vol.thetaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL));
		System.out.println("\tCálculo das Gregas - THETA (PUT)  : "
				+ vol.thetaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT));

		System.out.println("\tCálculo das Gregas - VEGA         : "
				+ vol.vegaBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d));
		
		System.out.println("\tCálculo das Gregas - RHO (CALL)   : "
				+ vol.rhoBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.CALL));
		System.out.println("\tCálculo das Gregas - RHO (PUT)    : "
				+ vol.rhoBlackScholes(120d, 100d, 0.4d, 0.1d, 1d, 0d, CalculoPrecoOpcaoValues.PUT));
		
		System.out.println(">>>> Fim - Volatilidade");
	}

	
	/**
	 * calculoVol
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 13/05/2011
	 * 
	 * @param dStrike
	 * @param dVencto
	 * @return
	 */
	private Double calculoVol(double dStrike, double dVencto) {

		int iStrike1 = 70;
		int iStrike2 = 80; 
		int iVencto1 = 30;
		int iVencto2 = 90;
		
		double dStrike1Vencto1 = 0.22D;
		double dStrike1Vencto2 = 0.23D;
		double dStrike2Vencto1 = 0.2D;
		double dStrike2Vencto2 = 0.21D;
		
	    double dInterpolacaoVol = dStrike1Vencto1 + (dStrike - iStrike1) *(dStrike2Vencto1 - dStrike1Vencto1) / 
	    		(iStrike2 - iStrike1) + (dVencto - iVencto1) * ((iStrike2 - dStrike) / 
	    		(iStrike2 - iStrike1) * (dStrike1Vencto2 - dStrike1Vencto1) /
	    		(iVencto2 - iVencto1) + (dStrike - iStrike1) / 
	    		(iStrike2 - iStrike1) * (dStrike2Vencto2 - dStrike2Vencto1) / 
	    		(iVencto2 - iVencto1));
		
		return dInterpolacaoVol;
	}



	/**
	 * calculoPrecoBlackScholes (Lista) - Eh o preço de uma opcao europeia sobre uma acao
	 * que pague dividendos a uma taxa continua e conhecida.
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 24/05/2011
	 * 
	 * @param pListCalculoPrecoOpcaoTO
	 * @return calculoPrecoBlackScholes
	 */
	public ArrayList<Double> calculoPrecoBlackScholes(List<CalculoPrecoOpcaoTO> pListCalculoPrecoOpcaoTO) {
		
		ArrayList<Double> listResult = new ArrayList<Double>();
		for (CalculoPrecoOpcaoTO precoOpcaoTO : pListCalculoPrecoOpcaoTO) { 
			listResult.add(calculoPrecoBlackScholes(precoOpcaoTO.getdS(), precoOpcaoTO.getdX(), precoOpcaoTO.getdVol(),
					precoOpcaoTO.getDrF(), precoOpcaoTO.getdT(), precoOpcaoTO.getdQ(), precoOpcaoTO.getdTipoOpcao()));
		}
	
		return listResult;
	}

	
	/**
	 * calculoPrecoBlackScholes - � o pre�o de uma op��o europ�ia sobre uma a��o que
	 * pague dividendos a uma taxa cont�nua e conhecida.
	 * Para este c�lculo � necess�rio calcular a probabilidade de se obter um valor 
	 * menor ou igual a z de uma vari�vel alet�ria normalmente distribu�da, com 
	 * m�dia 0 e vari�ncia 1, utilizando-se da fun��o: NormalCDF(z).
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 13/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @return
	 */
	private Double calculoPrecoBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao) {

		double dPrecoBlackScholes = 0d;
		double dAux1 = 0d;
		double dAux2 = 0d;

		dAux1 = (Math.log(pS / pX) + (prF + Math.pow(pVol, 2) / 2) * pT) / (pVol * Math.sqrt(pT)); 
		dAux2 = dAux1 - pVol * Math.sqrt(pT);

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
			dPrecoBlackScholes = pS * normalCDF(dAux1) * Math.exp(-pQ * pT) - pX * Math.exp(-prF * pT) * normalCDF(dAux2);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
			dPrecoBlackScholes = pX * Math.exp(-prF * pT) * normalCDF(-dAux2) - pS * normalCDF(-dAux1) * Math.exp(-pQ * pT);
		}
		
		return dPrecoBlackScholes;
	}



	/**
	 * calculoPrecoBinomial (Lista) - Sera utilizado um modelo do "discrete-time" 
	 * do preco variando sobre o tempo do instrumento financeiro. O valuation da 
	 * opcao eh computado entao atraves da aplicacao da neutralizacao do risco a 
	 * suposicao sobre a vida da opcao e como o preco do instrumento evolui.
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 25/05/2011
	 * 
	 * @param pListCalculoPrecoOpcaoTO
	 * @return calculoPrecoBinomial
	 */
	public ArrayList<Double> calculoPrecoBinomial(List<CalculoPrecoOpcaoTO> pListCalculoPrecoOpcaoTO) {
		ArrayList<Double> listResult = new ArrayList<Double>();
		for (CalculoPrecoOpcaoTO precoOpcaoTO : pListCalculoPrecoOpcaoTO) { 
			listResult.add(calculoPrecoBinomial(precoOpcaoTO.getdS(), precoOpcaoTO.getdX(), 
					precoOpcaoTO.getdVol(), precoOpcaoTO.getDrF(), precoOpcaoTO.getdT(), precoOpcaoTO.getdQ(),
					precoOpcaoTO.getdTipoOpcao(), precoOpcaoTO.getdN(), precoOpcaoTO.getdEstilo()));
	}
		return listResult;
	}
	
	
	/**
	 * calculoPrecoBinomial - Ser� utilizado um modelo do �discrete-time� do 
	 * pre�o variando sobre o tempo do instrumento financeiro. O valuation da 
	 * op��o � computado ent�o atrav�s da aplica��o da neutraliza��o do risco 
	 * a suposi��o sobre a vida da op��o e como o pre�o do instrumento evolui.
	 *
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 15/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pvol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @param pN			n�mero de passos da �rvore
	 * @param pEstilo		americana ou europ�ia
	 * @return
	 */
	private Double calculoPrecoBinomial(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao, double pN, EstiloValues pEstilo) {	

	    double dT = 0d;
	    double dU = 0d;
	    double dD = 0d;
	    double dP = 0d;

	    // tamanho do passo no tempo
	    dT = pT / pN;

	    // quanto o pre�o do ativo sobe no estado de alta (up)
	    // e quanto cai no estado de  baixa (down)
	    dU = Math.exp(pVol * Math.sqrt(dT));
	    dD = 1 / dU;
	    
	    // probabilidade de subida
	    dP = (Math.exp((prF - pQ) * dT) - dD) / (dU - dD);

	    // Inicializa as matrizes da �rvore de
	    // pre�os do ativo sTree e do derivativo fTree,
	    // ambas de dimens�o n+1 X n+1
	    Double[][] sTree = new Double[(int)pN+1][(int)pN+1];
	    Double[][] fTree = new Double[(int)pN+1][(int)pN+1];

	    // Constr�i a �rvore de pre�os do ativo seguindo um processo binomial
	    for (int i = 0; i <= (int)pN; i++) {
			for (int j = i; j <= (int)pN; j++) 
				sTree[i][j] = pS * Math.pow(dD,i) * Math.pow(dU, (j - i));
		}

	    // �ltima coluna da �rvore de pre�os:
	    // basta aplicar o m�todo payOff, pois o pre�o do derivativo � conhecido
	    // no seu vencimento
	    for (int i = 0; i <= (int)pN; i++) 
			fTree[i][(int)pN] = payOff(sTree[i][(int)pN].doubleValue(), pX, pTipoOpcao); 

	    // Dado que o pre�o do derivativo � conhecido no �ltimo instante,
	    // agora � s� voltar para tr�s na �rvore, calculando o pre�o esperado
	    // descontado em cada n�. Aten��o: de tr�s p/ frente!
	    
	    // Se a op��o for americana, testar para checar se seu valor intr�nseco
	    // � maior do que o seu pre�o esperado. Se for, ela � exercida.
	    for (int j = (int)pN-1; j >= 0; j--) { 
			for (int i = 0; i <= j; i++) { 
				fTree[i][j] = Math.exp(-(prF - pQ) * dT) * (dP * fTree[i][j+1].doubleValue() + (1 - dP) * fTree[i+1][j+1].doubleValue());
				
				if (pEstilo.equals(EstiloValues.AMERICANA) && payOff(sTree[i][j].doubleValue(), pX, pTipoOpcao) > fTree[i][j].doubleValue()) {
					fTree[i][j] = payOff(sTree[i][j].doubleValue(), pX, pTipoOpcao);
				}
			}
		}
	    
	    double dPrecoBinomial = fTree[0][0].doubleValue();

	    return dPrecoBinomial;
	}

	
	
	/**
	 * calculoPrecoGarmanKolhagen (Lista)
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 25/05/2011
	 * 
	 * @param pListCalculoPrecoOpcaoTO
	 * @return
	 */
	public ArrayList<Double> calculoPrecoGarmanKolhagen(List<CalculoPrecoOpcaoTO> pListCalculoPrecoOpcaoTO) {
		ArrayList<Double> listResult = new ArrayList<Double>();
		for (CalculoPrecoOpcaoTO precoOpcaoTO : pListCalculoPrecoOpcaoTO) { 
			listResult.add(calculoPrecoGarmanKolhagen(precoOpcaoTO.getdS(), precoOpcaoTO.getdX(), 
					precoOpcaoTO.getdVol(), precoOpcaoTO.getDrF(), precoOpcaoTO.getdT(), precoOpcaoTO.getdQ(),
					precoOpcaoTO.getdTipoOpcao(), precoOpcaoTO.getdN()));
	}
		return listResult;
	}
	
	
	/**
	 * calculoPrecoGarmanKolhagen
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 13/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @param pN			n�mero de passos da �rvore
	 * @return
	 */
	private Double calculoPrecoGarmanKolhagen(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao, double pN) {

		double dPrecoGarmanKolhagen = 0d;
		double d1 = 0d;
		double d2 = 0d;
		// double u = 0d; //FIXME - N�O UTILIZADO
		// double d = 0d; //FIXME - N�O UTILIZADO
		double dt = 0d;

	    // tamanho do passo no tempo
	    dt = pT / pN;

	    // FIXME - TRECHO COMENTADO, POIS, N�O ESTAVA SENDO UTILIZADO NO C�LCULO
	    // quanto o pre�o do ativo sobe no estado de alta (up) e quanto cai no estado de baixa (down)
	    // u = Math.exp(pVol * Math.sqrt(dt));
	    // d = 1 / u;

	    d1 = (Math.log(pS / pX) + (prF - pQ + Math.pow(pVol, 2d) / 2d) * dt) / (pVol * Math.sqrt(dt));
	    d2 = d1 - pVol * Math.sqrt(pT);

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
	    	dPrecoGarmanKolhagen = pS * normalCDF(d1) * Math.exp(-pQ * pT) - pX * Math.exp(-prF * pT) * normalCDF(d2);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
	    	dPrecoGarmanKolhagen = pX * Math.exp(-prF * pT) * normalCDF(-d2) - pS * normalCDF(-d1) * Math.exp(-pQ * pT);
		}
	    
		return dPrecoGarmanKolhagen;
	}

	//FIXME - PAROU AQUI!
	
	/**
	 * calculoPrecoBlack
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 13/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @param pN			n�mero de passos da �rvore
	 * @return
	 */
	private Double calculoPrecoBlack(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao, double pN) {

		double dPrecoBlack = 0d;
		double d1 = 0d;
		double d2 = 0d;
		// double u = 0d; //FIXME - N�O UTILIZADO
		// double d = 0d; //FIXME - N�O UTILIZADO
		double dt = 0d;

	    // tamanho do passo no tempo		
	    dt = pT / pN;

	    // FIXME - TRECHO COMENTADO, POIS, N�O ESTAVA SENDO UTILIZADO NO C�LCULO
	    // quanto o pre�o do ativo sobe no estado de alta (up) e quanto cai no estado de baixa (down)
	    // u = Math.exp(pVol * Math.sqrt(dt));
	    // d = 1 / u;

	    d1 = (Math.log(pS / pX) + (prF - pQ + Math.pow(pVol, 2d) / 2d) * dt) / (pVol * Math.sqrt(dt));
	    d2 = d1 - pVol * Math.sqrt(pT);

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
	    	dPrecoBlack = pS * normalCDF(d1) * Math.exp(-pQ * pT) - pX * Math.exp(-prF * pT) * normalCDF(d2);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
	    	dPrecoBlack = pX * Math.exp(-prF * pT) * normalCDF(-d2) - pS * normalCDF(-d1) * Math.exp(-pQ * pT);
		}
	    
		return dPrecoBlack;
	}


	/**
	 * deltaBlackScholes - Diz quantos centavos o pre�o da op��o vai subir, se o pre�o
	 * da a��o subjacente subisse $1. A op��o PETRH30 possui delta de 79 centavos. Ou
	 * seja, a op��o sobe 79 centavos para cada real de aumento em PETR4
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 14/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @return
	 */
	private double deltaBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao) {
		
		double dDeltaBlackScholes = 0d;

		double d1 = (Math.log(pS / pX) + (prF + Math.pow(pVol, 2d) / 2d) * pT) / (pVol * Math.sqrt(pT));

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
			dDeltaBlackScholes = normalCDF(d1) * Math.exp(-pQ * pT);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
			dDeltaBlackScholes = (normalCDF(d1) - 1d) * Math.exp(-pQ * pT);
		}
			
		return dDeltaBlackScholes;
	}

	
	/**
	 * gamaBlackScholes - Indica quanto o DELTA iria variar, quando a a��o
	 * subjacente subisse $1. A PETRH30 possui gama de 11 centavos. Ou seja,
	 * se PETR4 subir de 31,45 para 32,45, o DELTA j� passaria a ser de
	 * 0,90 centavos (79+11)
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 14/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @return
	 */
	private double gamaBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ) {
		
		double d1 = (Math.log(pS / pX) + (prF + Math.pow(pVol, 2d) / 2d) * pT) / (pVol * Math.sqrt(pT));
		double dGamaBlackScholes = normalPDF(d1) * Math.exp(-pQ * pT) / (pS * pVol * Math.sqrt(pT));
		
		return dGamaBlackScholes;
	}

	
	/**
	 * thetaBlackScholes - Indica quanto o valor da op��o ir� mudar pela passagem
	 * do tempo. O theta da PETRH30 � igual a 2 centavos por dia. O resultado � 
	 * sempre negativo, pois na verdade o valor da op��o � quase todo uma 
	 * conseq��ncia do futuro incerto. Na medida que o tempo escoa, o futuro vai 
	 * chegando perto e o valor da op��o vai caindo.
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 14/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @return
	 */
	private double thetaBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao) {
		
		double dThetaBlackScholes = 0d;
		double d1 = 0d;
		double d2 = 0d;
		
		d1 = (Math.log(pS / pX) + (prF + Math.pow(pVol, 2d) / 2d) * pT) / (pVol * Math.sqrt(pT));
		d2 = d1 - pVol * Math.sqrt(pT);

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
			dThetaBlackScholes = -pS * normalPDF(d1) * pVol * Math.exp(-pQ * pT) / 
			(2 * Math.sqrt(pT)) + pQ * pS * normalCDF(d1) * Math.exp(-pQ * pT) -
			prF * pX * Math.exp(-prF * pT) * normalCDF(d2);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
			dThetaBlackScholes = -pS * normalPDF(d1) * pVol * Math.exp(-pQ * pT) /
			(2 * Math.sqrt(pT)) - pQ * pS * normalCDF(-d1) * Math.exp(-pQ * pT) +
			prF * pX * Math.exp(-prF * pT) * normalCDF(-d2);
		}
	
		return dThetaBlackScholes;
	}

	
	/**
	 * vegaBlackScholes - O vega faz an�lise da volatilidade da a��o. Quanto mais 
	 * vol�til, mais o vega influencia no pre�o. O vega, em teoria, estuda a 
	 * volatilidade futura, mas como � imposs�vel saber o que vai acontecer, ent�o 
	 * se usa a volatilidade passada para se calcular, mesmo sabendo que o resultado 
	 * poder� ser muito diferente do que de fato ir� ocorrer. Vega � pouco usada no 
	 * mercado, geralmente por profissionais do mercado.
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 14/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @return
	 */
	private double vegaBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ) {
			
		double d1 = (Math.log(pS / pX) + (prF + Math.pow(pVol, 2d) / 2d) * pT) / (pVol * Math.sqrt(pT));
		double dVegaBlackScholes = pS * Math.sqrt(pT) * normalPDF(d1) * Math.exp(-pQ * pT);
		
		return dVegaBlackScholes;
	}

	
	/**
	 * rhoBlackScholes - Influ�ncia das taxas de juros no pre�o. Quanto mais juros,
	 * maior o valor extr�nsico (VE) da op��o. Como no Brasil os juros s�o est�veis,
	 * o Rho t�m pouca influ�ncia no pre�o.
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 15/05/2011
	 * 
	 * @param pS			pre�o do ativo � vista
	 * @param pX			pre�o de exerc�cio da s�rie da op��o
	 * @param pVol			volatilidade do ativo
	 * @param prF			taxa de juros cont�nua sem risco da economia (dividendos)
	 * @param pT			tempo a decorrer at� o vencimento da op��o
	 * @param pQ			taxa cont�nua de remunera��o
	 * @param pTipoOpcao	se a op��o � de Compra - "call" ou venda - "put"
	 * @return
	 */
	private double rhoBlackScholes(double pS, double pX, double pVol, double prF, double pT, double pQ, CalculoPrecoOpcaoValues pTipoOpcao) {
		
		double dRhoBlackScholes = 0d;
		double d1 = 0d;
		double d2 = 0d;
		
		d1 = (Math.log(pS / pX) + (prF + Math.pow(pVol,2d) / 2d) / pT) / (pVol * Math.sqrt(pT));
		d2 = d1 - pVol * Math.sqrt(pT);

		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
			dRhoBlackScholes = pX * pT * Math.exp(-prF * pT) * normalCDF(d2);
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
			dRhoBlackScholes = -pX * pT * Math.exp(-prF * pT) * normalCDF(-d2);
		}
	
		return dRhoBlackScholes;
	}

	
	/**
	 * normalCDF
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 15/05/2011
	 * 
	 * @param pZ
	 * @return
	 */
	private Double normalCDF(double pZ) {
		
		double dNormalCDF = 0d;
		
		final double c1 = 2.506628d;
		final double c2 = 0.3193815d;
		final double c3 = -0.3565638d;
		final double c4 = 1.7814779d;
		final double c5 = -1.821256d;
		final double c6 = 1.3302744d;
		
		double dW = 0d;
		double dY = 0d;

	    if (pZ > 0 || pZ == 0) {
	    	dW = 1d;
	    } else {
	    	dW = -1d;
	    }

	    dY = 1d / (1d + 0.2316419d * dW * pZ);
    
	    dNormalCDF = 0.5d + dW * (0.5d - (Math.exp(-pZ * pZ / 2d) / c1) * (dY * (c2 + dY * (c3 + dY * (c4 + dY * (c5 + dY * c6)))))); 
	    
	    return dNormalCDF;
	}

	
	/**
	 * normalPDF
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 15/05/2011
	 * 
	 * @param pZ
	 * @return
	 */
	private double normalPDF(double pZ) {
		
		double dNormalPDF = 1d / (Math.sqrt(2d * Math.PI) * Math.exp(Math.pow(-pZ, 2d) / 2d));
		
		return dNormalPDF;
	}

	
	/**
	 * payOff
	 * 
	 * @author Marcelo A. Filipov (marcelof@infoserver.com.br)
	 * @since 15/05/2011
	 * 
	 * @param pS
	 * @param pX
	 * @param pTipoOpcao
	 * @return
	 */
	private Double payOff(double pS, double pX, CalculoPrecoOpcaoValues pTipoOpcao) {
	
		Double dPayOff = 0d;
		
		if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.CALL)) {
			dPayOff = (pS > pX) ? (pS - pX) : 0d;
		} else if (pTipoOpcao.equals(CalculoPrecoOpcaoValues.PUT)) {
			dPayOff = (pS < pX) ? (pX - pS) : 0d;
		}
			
		return dPayOff;
	}
	
}
